iT邦幫忙

2024 iThome 鐵人賽

0
自我挑戰組

30天的自我成長紀錄系列 第 14

[2024鐵人賽]第13天:Clean Code_chap. 3 函式

  • 分享至 

  • xImage
  •  

🖊️章節重點

-函式的準則

-重構函式的範例

🖊️ 函式的準則

作者認為函式是動詞,類別是名詞。程式設計師在撰寫程式時,就像在說故事,需要整潔地結合,並形成精確又清楚的語言。以下列舉撰寫函式時,建議遵守的準則。

(一) 簡短

  1. 2-4行長度,且一清二楚,還能帶領你到下一個函式。
  2. 函式的縮排程度不應大過一或兩層,大到包含巢狀結構。

(二) 只做一件式

  1. 取決於是否能從一函式中提煉出另一個函式
  2. 不只做一件事的範例:還能分成不同區塊(Listing 4-7)
 public static int[] generatePrimes(int maxValue)
 {
     if (maxValue >= 2) 
     {
         //declarations
         ...
         //initialize array to true
         ...
         //sieve
         ...
     }
 }

(三) 每個函式只有一層抽象概念

由上而下閱讀程式碼: 降層準則,就像閱讀由上而下的敘事,範例如下:

private void includeSetupAndTeardownPages() throws Exception{
    includeSetupPages();
    includePageContent();
    includeTeardownPages();
    updatePageContent();
}

private void includeSetupPages() throws Exception{
    if (isSuite)
        includeSuiteSetupPage();
    includeSetupPage();
}

private void includeSuiteSetupPage() throws Exception{
    include(SuiteResponder.SUITE_SETUP_NAME, "-setup");
}

private void includeSetupPage() throws Exception{
    include(""SetUp, "-setup");
}

(四) Switch敘述

(五) 函式的參數

  1. 單一參數的函示
  2. 旗標(flag)參數
  3. 兩個參數的函示
  4. 三個參數的函示
  5. 物件型態的參數
  6. 參數串列
  7. 動詞和關鍵字

(六)要無副作用

  1. 輸出行參數

(七)指令和查詢要分離

(八) 用例外處理取代回傳錯誤碼

  1. 原因:因為回傳錯誤碼通常意味著在某類別或列舉(enum)定義所有錯誤碼,但當error num改變,其他相關的類別就必須重新編譯。
  2. 例外處理的範例:

(九)不要重複自己

(十) 結構化程式設計

🖊️ 重構函式的範例

原本: (Listing 3-1)

public static String testableHtml(                      //自我重複:每次都setup,suitesetup...
    PageData pageData
    boolean includeSuiteSetup
) throws Exception {
    WikiPage wikiPage = pageData.getWikiPage();
    StringBuffer buffer = new StringBuffer();
    if (pageData.hasAttribute("Test")){                              //巢狀結構,縮排超過兩層
     if (includeSuiteSetup){
         WikiPage suiteSetup=
            pageCrawlerImpl.getInheritedPage(
                 SuiteResponder.SUITE_SETUP_NAME, wikiPage
            );
        if (suiteSetup != null){
            WikiPagePath pagePath = 
              suiteSetup.getPageCrawler().getFullPath(suiteSetup);
                    String pagePath = PathParser.render(pagePath);  //不同層次同時存在:中層次
                    buffer.append("!include -setup .")              //不同層次同時存在:低層次
                          .append(pagePathName)
                          .append("\n");
        }
     }
     WikiPage suiteSetup=......
    }
}

經過整章節一步步重構後: (Listing 3-7)

package fitness.html;

import fitness.responder.run.SuiteResponder;
import fitness.wiki.*;

public class SetupTeardownIncluder{
    private PageData pageData;
    private boolean isSuite;
    private WikiPage testPage;
    private StringBuffer newPageContent;
    private PageCrawler pageCrawler;
    
    public static String render(PageData pageData) throws Exception {
    return render(pageData, false);
    }
    
    public static String render(PageData pageData, boolean isSuite) throws Exception{
    return new SetupTeardownIncluder(pageData).render(isSuite);
    }
    
    private SetupTeardownIncluder(PageData pageData){
    this.pageData = pageData;
    testPage = pageData.getWikiPage();
    pageCrawler = testPage.getPageCrawler();
    newPageContent = new StringBuffer();
    }
    
    private String render(boolean isSuite) throws Exception{
    this.isSuite = isSuite;
    if (isTestPage())
         includeSetupAndTeardownPages();                           //由上而下
    return pageData.getHtml();
    }
    
    private boolean isTestPage() throws Exception{
    return pageData.hasAttribute("Test");
    }
    
    private void includeSetupAndTeardownPages() throws Exception{   //由上而下
    includeSetupPages();
    includePageContent();
    includeTeardownPages();
    updatePageContent();
}

    ....

}

📖 下一章節主題預告

在了解基本定義後,下一章要談的是註解。


上一篇
[2024鐵人賽]第12天:Clean Code_chap. 2 有意義的命名
系列文
30天的自我成長紀錄14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言